﻿// Inner Fire 游戏引擎库
// PhysicsBone - 动态服装/骨骼
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 动态服装/骨骼。使用Verlet粒子进行简单的物理骨骼模拟。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-06-19

#pragma once

#include <EASTL/vector.h>
#include <game/component/component.h>
#include <game/physics/physics_bone_setting.h>
#include <graphics/transform_def.h>
#include <memory>

namespace ifire::game {
class Animator;
class Armature;
struct ArmatureNode;
class Avatar;
class PhysicsBone;
class PhysicsParticleTree;

struct PhysicsParticle {
  PhysicsParticle(PhysicsParticleTree& parent, int index);

  int index;
  int bone_id;
  ArmatureNode* node;

  Trans3 transform;
  int parent_index;
  int child_count;
  float damping;
  float elasticity;
  float stiffness;
  float inert;
  float friction;
  float radius;
  float bone_length;
  bool is_collide;
  bool transform_not_null;

  IVec position;
  IVec prev_position;
  IVec rest_position;
  IVec end_offset;

  // prepare data
  IVec transform_position;
  IVec transform_local_position;
  IMat transform_local_to_world_matrix;

  PhysicsParticleTree& parent;

  PhysicsParticle& GetParent();
};

class PhysicsParticleTree {
public:
  PhysicsParticleTree(PhysicsBone& parent, const PhysicsBoneSetting& setting);

public:
  // 根骨骼的ID
  int root_id;
  // 此节点所采用的配置
  const PhysicsBoneSetting& setting;
  // 此节点积累的Wave
  IVec wave;
  // Wave的相对位置（因为粒子是用绝对Position计算的）
  IVec wave_world;
  // 用于进行反转的项目
  float wave_flip;
  // 用于累积wave
  float wave_tick;

  IVec local_gravity;
  IMat root_world_to_local_matrix;
  float bone_total_length;
  eastl::vector<PhysicsParticle> particles;

  // prepare data
  IVec3 rest_gravity;

  PhysicsBone& parent;
};

using PhysicsParticleTreePtr = std::unique_ptr<PhysicsParticleTree>;

class PhysicsBone : public Component {
public:
  PhysicsBone(GameObject* game_object);
  PhysicsBone(const PhysicsBone& lhs) = delete;
  PhysicsBone& operator=(const PhysicsBone& lhs) = delete;
  ~PhysicsBone() override;

  // 每帧更新
  void FixedUpdate(float delta_time) override;
  // 延迟更新
  void LateUpdate(float delta_time) override;

  // 执行一次更新（由Animator进行骨骼变换后调用）
  void UpdatePhysics(float delta_time);

  // 获得此项目的类型
  static ikit::sstr ComponentType();
  // 获得Meta名称
  const char* GetMetaName() override;

private:
  // 依次将骨骼读入
  void FillBones(PhysicsParticleTree* tree, ArmatureNode* node,
      int parent_index, float bone_length);
  // 创建尾端骨骼
  void AddEndBone(
      PhysicsParticleTree* tree, int parent_index, float bone_length);
  // 更新每一个粒子
  void UpdateParticle(PhysicsParticle& p);
  // 对粒子进行修正
  void AdjustParticle(PhysicsParticle& p);
  // 设置回骨骼
  void ApplyParticle(PhysicsParticle& p);

  Animator* animator_;
  const Armature* armature_;
  const Avatar* avatar_;
  eastl::vector<PhysicsParticleTreePtr> trees_;
  float delta_time_;
  IMat trans_mat_;
  IMat inv_trans_mat_;
  // 当前Object的位置
  IVec object_position_;
  // 上一帧Object的位置
  IVec prev_object_position_;
  // 在当前帧中Object产生的移动
  IVec object_move_;
  // 当前移动的长度
  IVec object_move_length_;
  // 是否记录
  bool is_logable_;
  // 记录的Tick
  float log_tick_;
};

} // namespace ifire::game